home *** CD-ROM | disk | FTP | other *** search
- /*
- File: ControlBackground.c
-
- Contains: ControlBackground, a quickie sample which shows how to
- affect the background color of a control when drawing it.
-
- Written by: Pete Gontier
-
- Copyright: Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/19/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- #include <Fonts.h>
- #include <Dialogs.h>
- #include <QDOffscreen.h>
- #include <Gestalt.h>
- #include <Appearance.h>
- #include <Sound.h>
- #include <LowMem.h>
-
- #include "MoveableModalDialog.h"
-
- enum
- {
- kDialogItemIndex_DrawButton = 3,
- kDialogItemIndex_CheckBox
- };
-
- static GrafPtr LMGetWMgrCPort (void) { return *(GrafPtr*)0x0D2C; }
- #define IsColorGrafPort(port) (((port)->portBits.rowBytes & 0xC000) == 0xC000)
-
- static pascal OSErr InitMac (void)
- {
- MaxApplZone ( );
- InitGraf (&(qd.thePort));
- InitFonts ( );
- InitWindows ( );
- InitMenus ( );
- TEInit ( );
- InitDialogs (nil);
-
- return noErr;
- }
-
- static pascal OSStatus IsAppearancePresent (Boolean *haveAppearance)
- {
- OSStatus err = noErr;
-
- long response;
-
- if (!(err = Gestalt (gestaltAppearanceAttr,&response)))
- *haveAppearance = response & (1 << gestaltAppearanceExists);
- else if (err == gestaltUndefSelectorErr)
- {
- *haveAppearance = false;
- err = noErr;
- }
-
- return err;
- }
-
- static pascal ControlRef NewUserPaneControl
- (WindowPtr window, const Rect *bounds, Boolean visible, UInt16 featureFlags)
- {
- return NewControl (window,bounds,"\p",visible,featureFlags,0,0,kControlUserPaneProc,0);
- }
-
- static pascal OSErr AtLeastOneParentHasSpecialBackground (ControlRef control, Boolean *alophsb)
- {
- //
- // This function walks up the control hierarchy looking for
- // a control which provides a special background. We need
- // to know this in order to decide whether the only way for
- // us to affect the background color is to go to the trouble
- // of creating a user pane control.
- //
-
- OSErr err = noErr;
-
- ControlHandle root;
-
- *alophsb = false;
-
- if (!(err = GetRootControl ((**control).contrlOwner, &root)))
- {
- if (!root)
- err = errNoRootControl;
- else
- {
- ControlRef scan = control;
-
- while (scan != root)
- {
- UInt32 features;
-
- err = GetSuperControl (scan,&scan);
- if (err) break;
- err = GetControlFeatures (scan,&features);
- if (err) break;
-
- if (features & kControlHasSpecialBackground)
- {
- //
- // In at least 8.6 and earlier (and perhaps later),
- // CreateRootControl spuriously sets
- // kControlHasSpecialBackground. [Radar 2324373]
- // We work around this weirdness here by checking
- // to see if a proc has been assigned. If the bug
- // gets fixed, this code will be a little less
- // than optimally efficient but will still be
- // correct (I hope).
- //
-
- if (scan != root)
- {
- *alophsb = true;
- break;
- }
- else
- {
- ControlUserPaneBackgroundUPP upp;
- Size actualSize;
-
- if (!(err = GetControlData (scan,kControlNoPart,
- kControlUserPaneBackgroundProcTag,sizeof(upp),(Ptr)&upp,&actualSize)))
- {
- if (sizeof (upp) != actualSize)
- err = paramErr;
- else if (upp)
- {
- *alophsb = true;
- break;
- }
- }
- }
- }
- }
- }
- }
-
- return noErr;
- }
-
- static pascal void ControlUserPaneBackgroundProc (ControlHandle control, ControlBackgroundPtr)
- {
- //
- // This function is called by the user pane CDEF. Its
- // job is to setup the background of the current graphics
- // port in some "special" way. All we want is to set the color.
- // The appearance-savvy thing to do when setting the color is
- // to also set the pattern (and vice versa).
- //
-
- BackPat (&(qd.white));
- RGBBackColor ((const RGBColor *) GetControlReference (control));
- }
-
- #pragma mark -
-
- static pascal OSErr Draw1ControlWithBackgroundColorViaWindowColorTable
- (ControlRef control, const RGBColor *rgb)
- {
- //
- // Walk the color table of the given control's
- // window looking for the content color.
- //
-
- AuxWinHandle auxWinHandle;
- WindowRef contrlOwner = (**control).contrlOwner;
- Boolean oldColorTableWasDefault = GetAuxWin (contrlOwner,&auxWinHandle);
- WCTabHandle winCTabHandle = (WCTabHandle) ((**auxWinHandle).awCTable);
- short ctIndex = (**winCTabHandle).ctSize;
-
- while (ctIndex > -1)
- {
- ColorSpecPtr rgbScan = ctIndex + (**winCTabHandle).ctTable;
-
- if (rgbScan->value == wContentColor)
- {
- RGBColor savedRGB = rgbScan->rgb;
- rgbScan->rgb = *rgb;
- CTabChanged ((CTabHandle) winCTabHandle);
- Draw1Control (control);
- // assume memory has moved and rgbScan has become stale
- (**winCTabHandle).ctTable [ctIndex].rgb = savedRGB;
- CTabChanged ((CTabHandle) winCTabHandle);
- return noErr; // bail out of function without exiting loop
- }
-
- --ctIndex;
- }
-
- //
- // If the content color was found, the rest of this function
- // will not execute; there is a return statement inside the
- // loop, above.
- //
- // We take a lack of a content color to mean that we've been
- // passed a control which lives in a bogus window, and we claim
- // this is a parameter error. However, it's conceivable that
- // we could deal with this by either creating a color table
- // for this window or adding an entry to the table which is
- // already there. This kind of thing is beyond the scope of
- // this sample. You only have to worry about this issue if
- // you are creating your own window color tables and don't
- // always include a content color. Resource editors generally
- // create an entry for the content color even if you
- // only customized some other color in the table.
- //
-
- return paramErr;
- }
-
- static pascal OSErr Draw1ControlWithBackgroundColorViaOwningGrafPort
- (ControlRef control, const RGBColor *rgb)
- {
- //
- // Our job here is simple; set the background color of the
- // graphics port into which the control will be drawn and
- // then draw the control. The interesting wrinkle is that
- // if the control's owning port is monochrome, it will draw
- // into the Window Manager's color port. Nasty! The only
- // way to do the right thing here is to muck with low memory.
- // There is not even an LM accessor for what we need to do!
- // This is actively Carbon-hostile, which means this sample
- // will have to be updated again for Carbon. Sigh...
- //
-
- RGBColor preservedBackColor;
- GrafPtr preservedPort = qd.thePort;
- GrafPtr targetPort = (**control).contrlOwner;
-
- if (!IsColorGrafPort (targetPort))
- targetPort = LMGetWMgrCPort ( );
-
- preservedBackColor = ((CGrafPtr) targetPort)->rgbBkColor;
-
- SetPort (targetPort);
- RGBBackColor (rgb);
- Draw1Control (control);
- RGBBackColor (&preservedBackColor);
-
- return noErr;
- }
-
- static pascal OSErr Draw1ControlWithBackgroundColorViaUserPane
- (ControlRef child, const RGBColor *rgb)
- {
- //
- // This is the most complicated part of this sample.
- // We call the control which we want to draw "the child".
- // We create a user pane control which will be the parent of
- // the child. We associate a special background setup proc
- // with the user pane. The user pane is considered to be
- // "behind" the child for purposes of the special background
- // proc, so the user pane gets to dictate the background for
- // the child. After we're done drawing the child, we restore
- // it to its original parent and blow away the user pane.
- //
-
- OSErr err = noErr;
-
- ControlRef parent;
-
- if (!(err = GetSuperControl (child,&parent)))
- {
- Rect userPaneBounds = (**child).contrlRect;
- GrafPtr userPaneOwner = (**child).contrlOwner;
- const UInt32 userPaneFF = kControlSupportsEmbedding | kControlHasSpecialBackground;
- ControlRef userPane = NewUserPaneControl (userPaneOwner,&userPaneBounds,true,userPaneFF);
-
- if (!userPane)
- err = nilHandleErr;
- else
- {
- OSErr err2;
-
- if (!(err = EmbedControl (userPane,parent)))
- if (!(err = EmbedControl (child,userPane)))
- {
- ControlUserPaneBackgroundUPP upp =
- NewControlUserPaneBackgroundProc (ControlUserPaneBackgroundProc);
-
- if (!upp)
- err = nilHandleErr;
- else
- {
- if (!(err = SetControlData (userPane,kControlNoPart,
- kControlUserPaneBackgroundProcTag,sizeof(upp),(Ptr)&upp)))
- {
- SetControlReference (userPane,(long)rgb);
- Draw1Control (child);
- }
- DisposeRoutineDescriptor (upp);
- }
- err2 = EmbedControl (child,parent);
- if (!err) err = err2;
- }
-
- err2 = SetControlVisibility (userPane,false,false);
- if (!err) err = err2;
- DisposeControl (userPane);
- }
- }
-
- return noErr;
- }
-
- static pascal OSErr Draw1ControlWithBackgroundColor (ControlRef control, const RGBColor *rgb)
- {
- //
- // This function decides which technique to use for drawing
- // the control with the appropriate background based on what
- // APIs are available and the state of the control's owning
- // window.
- //
-
- OSErr err = noErr;
-
- Boolean haveAppearance;
-
- if (!(err = IsAppearancePresent (&haveAppearance)))
- {
- if (!haveAppearance)
- err = Draw1ControlWithBackgroundColorViaWindowColorTable (control,rgb);
- else
- {
- ControlHandle rootControl;
-
- err = GetRootControl ((**control).contrlOwner, &rootControl);
-
- if (err == errNoRootControl || !rootControl)
- err = Draw1ControlWithBackgroundColorViaOwningGrafPort (control,rgb);
- else
- {
- Boolean special;
-
- if (!(err = AtLeastOneParentHasSpecialBackground (control,&special)))
- {
- if (!special)
- err = Draw1ControlWithBackgroundColorViaOwningGrafPort (control,rgb);
- else
- err = Draw1ControlWithBackgroundColorViaUserPane (control,rgb);
- }
- }
- }
- }
-
- return err;
- }
-
- #pragma mark -
-
- void main (void)
- {
- if (InitMac ( ))
- SysBeep (10);
- else
- {
- DialogRef dlgRef = GetNewDialog (129,nil,(WindowRef)-1);
- if (dlgRef)
- {
- short itemHit;
-
- SetDialogDefaultItem (dlgRef,kStdOkItemIndex);
- ShowWindow (dlgRef);
- InitCursor ( );
-
- do
- {
- MoveableModalDialog (NewModalFilterProc(StdFilterProc),&itemHit);
-
- if (itemHit == kDialogItemIndex_DrawButton)
- {
- short iType; Handle iHandle; Rect iRect;
- RGBColor periwinkle = { 0x5555,0x5555,0xFFFF };
-
- GetDialogItem (dlgRef,kDialogItemIndex_CheckBox,&iType,&iHandle,&iRect);
- if (Draw1ControlWithBackgroundColor ((ControlRef)iHandle, &periwinkle))
- SysBeep (10);
- }
- }
- while (itemHit != kStdOkItemIndex);
-
- DisposeDialog (dlgRef);
- }
- }
- }
-